using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;

namespace Speedball2 {
  public class ScoreMultipliers {
    public int _team1;
    public int _team2;
    public int _pAnim;
    public int _animIndex;
    public Point _originXY;

    public List<Entity> _entities;
    public Entity _entityA = new Entity (Game.AtariDisk, Game.AtariRamToDisk (0x4A6A));
    public Entity _entityB = new Entity (Game.AtariDisk, Game.AtariRamToDisk (0x4A92));
    public Entity _entityC = new Entity (Game.AtariDisk, Game.AtariRamToDisk (0x4ABA));
    public Entity _entityD = new Entity (Game.AtariDisk, Game.AtariRamToDisk (0x4AE2));

    public ScoreMultipliers () {
      _team1 = 0;
      _team2 = 0;
      _pAnim = 0;
      _animIndex = 0;
      _originXY = Point.Empty;

      _entityA.InitScoreMultiplier (41);
      _entityB.InitScoreMultiplier (39);
      _entityC.InitScoreMultiplier (37);
      _entityD.InitScoreMultiplier (35);
      _entities = new List<Entity> ();
      _entities.Add (_entityA);
      _entities.Add (_entityB);
      _entities.Add (_entityC);
      _entities.Add (_entityD);
    }

    public void CheckEnter (Match match) {
      Entity ball = match.EntityBall;
      if (match.EntityHoldingBall != null)
        return;
      if (match.Bit2_IsBallInScoreMultiplier)
        return;
      if (ball._spriteIndex > 2)
        return;
      if ((ball._terrainXY.X < 24) || (ball._terrainXY.X > 616))
        return;
      int d2, d3;
      // left
      if (ball._terrainXY.X < 64) {
        d2 = 576;
        d3 = 640;
        if ((ball._terrainXY.Y > d3) || (ball._terrainXY.Y < d2))
          return;
        // entering
        if ((ball._terrainXY.X >= 48) &&
            ((ball._dir == 0) || (ball._dir == 4))) {
          if (ball._dir == 4)
            _pAnim = 0x2CE0;
          else
            _pAnim = 0x2C7C;
          match.Bit2_IsBallInScoreMultiplier = true;
          ball._pOpcodes = 0x55BE;
          ball._opcodeIndex = 0;
          _animIndex = 0;
          _originXY = new Point (0, d2);
        }
        // don't enter
        else {
          CheckBounce (match, true, d2, d3);
        }
      }
      // right
      else if (ball._terrainXY.X > 576) {
        d2 = 512;
        d3 = 576;
        if ((ball._terrainXY.Y > d3) || (ball._terrainXY.Y < d2))
          return;
        // entering
        if ((ball._terrainXY.X <= 592) &&
            ((ball._dir == 0) || (ball._dir == 4))) {
          if (ball._dir == 4)
            _pAnim = 0x2D44;
          else
            _pAnim = 0x2DA8;
          match.Bit2_IsBallInScoreMultiplier = true;
          ball._pOpcodes = 0x55BE;
          ball._opcodeIndex = 0;
          _animIndex = 0;
          _originXY = new Point (640, d2);
        }
        // don't enter
        else {
          CheckBounce (match, false, d2, d3);
        }
      }
    }

    private void CheckBounce (Match match, bool left, int y1, int y2) {
      Entity ball = match.EntityBall;
      int d0 = ball._terrainXY.X - 2 * ball._velocityXY.X;
      int d1 = ball._terrainXY.Y - 2 * ball._velocityXY.Y;
      // check bounce vertical
      if (((left) && (d0 >= 64)) ||
          ((!left) && (d0 <= 576))) {
        ball._velocityXY.X = -ball._velocityXY.X;
        ball._dir = Match.GetMirrorXFromDir (ball._dir);
      }
      // check bounce horizontal
      if ((d1 < y1) || (d1 > y2)) {
        ball._velocityXY.Y = -ball._velocityXY.Y;
        ball._dir = Match.GetMirrorYFromDir (ball._dir);
      }
      // todo: sound
    }

    public void UpdateInside (Match match) {
      if (!match.Bit2_IsBallInScoreMultiplier)
        return;
      Point offsetXY = GetOffsetXY ();
      Entity ball = match.EntityBall;
      if (offsetXY.IsEmpty) {
        match.SetBallSpeedFromThr (match.PlayerThrower._attributes._thr);
        match.Bit2_IsBallInScoreMultiplier = false;
        ball._pOpcodes = 0x5588;
        ball._opcodeIndex = 0;
        if (ball._velocityXY.Y >= 0)
          ball._velocityXY.Y = 8;
        else
          ball._velocityXY.Y = -8;
      }
      else {
        _animIndex++;
        ball._terrainXY.X = _originXY.X + offsetXY.X;
        ball._terrainXY.Y = _originXY.Y + offsetXY.Y;
        if (_animIndex == 22)
          UpdateLeds (match);
      }
    }

    private void UpdateLeds (Match match) {
      Player player = match.PlayerThrower;
      int entityIndex;
      bool? isTeamZero = null;
      bool? isTeamOne = null;
      if (!player.Bit3_IsTeam1_IsElectrobounced) {
        if (_team1 != 0) {
          entityIndex = 0;
          _team1--;
          if (_team1 == 0)
            isTeamZero = true;
          else
            isTeamZero = false;
        }
        else {
          entityIndex = 1;
          if (_team2 == 2)
            return;
          _team2++;
          if (_team2 == 1)
            isTeamOne = true;
          else
            isTeamOne = false;
        }
      }
      // Else1
      else {
        if (_team2 != 0) {
          entityIndex = 1;
          _team2--;
          if (_team2 == 0)
            isTeamZero = true;
          else
            isTeamZero = false;
        }
        else {
          entityIndex = 0;
          if (_team1 == 2)
            return;
          _team1++;
          if (_team1 == 1)
            isTeamOne = true;
          else
            isTeamOne = false;
        }
      }

      if (isTeamOne.HasValue) {
        if (!isTeamOne.Value) {
          _entities [entityIndex]._spriteIndex++;
          _entities [entityIndex + 2]._spriteIndex++;
        }
        else {
          _entities [entityIndex].Bit7_IsInvisible = false;
          _entities [entityIndex + 2].Bit7_IsInvisible = false;
        }
      }
      else if (isTeamZero.HasValue) {
        if (!isTeamZero.Value) {
          _entities [entityIndex]._spriteIndex--;
          _entities [entityIndex + 2]._spriteIndex--;
        }
        else {
          _entities [entityIndex].Bit7_IsInvisible = true;
          _entities [entityIndex + 2].Bit7_IsInvisible = true;
        }
      }
      else
        throw new Exception ();
    }

    private Point GetOffsetXY () {
      int offset = _pAnim + _animIndex * 2;
      return (new Point (Game.AtariDisk.ReadByteSigned (Game.AtariRamToDisk (offset)),
                         Game.AtariDisk.ReadByteSigned (Game.AtariRamToDisk (offset + 1))));
    }
  }
}
